From c9aef3fc4d6b3b81d7d1fc48ea8b7e9d749bb61c Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 4 Apr 2020 20:02:20 -0400 Subject: [PATCH] Add gdk_event_get_match This is a counterpart to gdk_event_matches() that can be used to obtain a shortcut matching an event. --- docs/reference/gdk/gdk4-sections.txt | 5 ++ gdk/gdkevents.c | 114 +++++++++++++++++++++++---- gdk/gdkevents.h | 15 ++++ 3 files changed, 119 insertions(+), 15 deletions(-) diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index fb0341f9b8..553982ca50 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -566,6 +566,11 @@ gdk_events_get_angle gdk_events_get_center gdk_events_get_distance + +GdkEventMatch +gdk_event_matches +gdk_event_get_match + GDK_TYPE_EVENT GDK_TYPE_EVENT_MASK diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 1d53d9c30b..5ab593eefb 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -2162,18 +2162,30 @@ translate_keyboard_accel_state (GdkKeymap *keymap, return retval; } - +/** + * gdk_event_matches: + * @event: the #GdkEvent + * @keyval: the keyval to match + * @modifiers: the modifiers to match + * + * Matches an event against a keyboard shortcut that is specified + * as a keyval and modifiers. Note that partial matches are possible + * where the combination matches if the currently active group is + * ignored. + * + * Returns: a GdkEventMatch value describing whether @event matches + */ GdkEventMatch gdk_event_matches (GdkEvent *event, - guint match_keyval, - GdkModifierType match_modifiers) + guint keyval, + GdkModifierType modifiers) { guint keycode; GdkModifierType state; GdkModifierType mask; int group; GdkKeymap *keymap; - guint keyval; + guint ev_keyval; int effective_group; int level; GdkModifierType consumed_modifiers; @@ -2181,7 +2193,7 @@ gdk_event_matches (GdkEvent *event, gboolean group_mod_is_accel_mod = FALSE; const GdkModifierType xmods = GDK_MOD2_MASK|GDK_MOD3_MASK|GDK_MOD4_MASK|GDK_MOD5_MASK; const GdkModifierType vmods = GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK; - GdkModifierType modifiers; + GdkModifierType mods; if (gdk_event_get_event_type (event) != GDK_KEY_PRESS) return GDK_EVENT_MATCH_NONE; @@ -2200,7 +2212,7 @@ gdk_event_matches (GdkEvent *event, translate_keyboard_accel_state (keymap, keycode, state, group, - &keyval, + &ev_keyval, &effective_group, &level, &consumed_modifiers); @@ -2215,10 +2227,10 @@ gdk_event_matches (GdkEvent *event, gdk_keymap_map_virtual_modifiers (keymap, &mask); gdk_keymap_add_virtual_modifiers (keymap, &state); - modifiers = match_modifiers; - if (gdk_keymap_map_virtual_modifiers (keymap, &modifiers) && - ((modifiers & ~consumed_modifiers & mask & ~vmods) == (state & ~consumed_modifiers & mask & ~vmods) || - (modifiers & ~consumed_modifiers & mask & ~xmods) == (state & ~consumed_modifiers & mask & ~xmods))) + mods = modifiers; + if (gdk_keymap_map_virtual_modifiers (keymap, &mods) && + ((mods & ~consumed_modifiers & mask & ~vmods) == (state & ~consumed_modifiers & mask & ~vmods) || + (mods & ~consumed_modifiers & mask & ~xmods) == (state & ~consumed_modifiers & mask & ~xmods))) { /* modifier match */ GdkKeymapKey *keys; @@ -2229,8 +2241,8 @@ gdk_event_matches (GdkEvent *event, /* Shift gets consumed and applied for the event, * so apply it to our keyval to match */ - key = match_keyval; - if (match_modifiers & GDK_SHIFT_MASK) + key = keyval; + if (modifiers & GDK_SHIFT_MASK) { if (key == GDK_KEY_Tab) key = GDK_KEY_ISO_Left_Tab; @@ -2238,12 +2250,12 @@ gdk_event_matches (GdkEvent *event, key = gdk_keyval_to_upper (key); } - if (keyval == key && /* exact match */ + if (ev_keyval == key && /* exact match */ (!group_mod_is_accel_mod || - (state & shift_group_mask) == (match_modifiers & shift_group_mask))) + (state & shift_group_mask) == (modifiers & shift_group_mask))) return GDK_EVENT_MATCH_EXACT; - gdk_keymap_get_entries_for_keyval (keymap, match_keyval, &keys, &n_keys); + gdk_keymap_get_entries_for_keyval (keymap, keyval, &keys, &n_keys); for (i = 0; i < n_keys; i++) { @@ -2266,3 +2278,75 @@ gdk_event_matches (GdkEvent *event, return GDK_EVENT_MATCH_NONE; } + +/** + * gdk_event_get_match: + * @event: a #GdkEvent + * @keyval: (out): return location for a keyval + * @modifiers: (out): return location for modifiers + * + * Gets a keyval and modifier combination that will cause + * gdk_event_match() to successfully match the given event. + * + * Returns: %TRUE on success + */ +gboolean +gdk_event_get_match (GdkEvent *event, + guint *keyval, + GdkModifierType *modifiers) +{ + GdkKeymap *keymap; + GdkModifierType mask; + guint keycode; + guint group; + guint key; + guint accel_key; + GdkModifierType accel_mods; + GdkModifierType consumed_modifiers; + + if (gdk_event_get_event_type (event) != GDK_KEY_PRESS) + return FALSE; + + keymap = gdk_display_get_keymap (gdk_event_get_display (event)); + + mask = gdk_keymap_get_modifier_mask (keymap, + GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK); + + keycode = gdk_key_event_get_keycode (event); + group = gdk_key_event_get_group (event); + accel_key = gdk_key_event_get_keyval (event); + accel_mods = gdk_event_get_modifier_state (event); + + if (accel_key == GDK_KEY_Sys_Req && + (accel_mods & GDK_MOD1_MASK) != 0) + { + /* HACK: we don't want to use SysRq as a keybinding (but we do + * want Alt+Print), so we avoid translation from Alt+Print to SysRq + */ + *keyval = GDK_KEY_Print; + *modifiers = accel_mods & mask; + return TRUE; + } + + translate_keyboard_accel_state (keymap, + keycode, + accel_mods, + group, + &key, NULL, NULL, &consumed_modifiers); + + accel_key = gdk_keyval_to_lower (key); + + if (accel_key == GDK_KEY_ISO_Left_Tab) + accel_key = GDK_KEY_Tab; + + accel_mods &= mask & ~consumed_modifiers; + + /* Put shift back if it changed the case of the key, not otherwise. */ + if (accel_key != key) + accel_mods |= GDK_SHIFT_MASK; + + *keyval = accel_key; + *modifiers = accel_mods; + + return TRUE; +} diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index 944047d946..6d5fa26dbf 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -428,6 +428,16 @@ gboolean gdk_events_get_center (GdkEvent *event1, double *x, double *y); +/** + * GdkEventMatch: + * @GDK_EVENT_MATCH_NONE: The key event does not match + * @GDK_EVENT_MATCH_PARTIAL: The key event matches if keyboard state + * (specifically, the currently active group) is ignored + * @GDK_EVENT_MATCH_EXACT: The key event matches + * + * The possible return values from gdk_event_matches() + * describe how well an event matches a given keyval and modifiers. + */ typedef enum { GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_PARTIAL, @@ -439,6 +449,11 @@ GdkEventMatch gdk_event_matches (GdkEvent *event, guint keyval, GdkModifierType modifiers); +GDK_AVAILABLE_IN_ALL +gboolean gdk_event_get_match (GdkEvent *event, + guint *keyval, + GdkModifierType *modifiers); + G_END_DECLS #endif /* __GDK_EVENTS_H__ */ -- 2.30.2